/***************************************************
*		 Copyright (c) 2018 MINE 田宇
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
***************************************************/

#include "GPU.h"
#include "GPUID.h"
#include "PCI.h"

#include <os/debug.h>
#include <arch/memio.h>
#include <arch/memory.h>
#include <os/driver.h>
#include <stddef.h>
#include <types.h>

struct PCI_Header_00 GPU_PCI_HBA;
struct PCI_Header_00 PCH_PCI_HBA;

unsigned char *GTTMMADR,*GTTADR,*GMADR;
unsigned long GTTMMSIZE,GTTSIZE,GMSIZE;
unsigned char *DSMADR;
unsigned long DSMSIZE;
unsigned char *GPIO_MMIO_ADR;
unsigned char *ASLSADR;
unsigned char *MCBARADR;
unsigned char *VBTADR;
unsigned char *ACPI_CLID;
unsigned int  MBoxes;

unsigned long GPU_install(unsigned long irq,void * arg)
{
	return 0;
}

void GPU_enable(unsigned long irq)
{
}

/*
hw_int_controller GPU_int_controller = 
{
	.enable = GPU_enable,
	.disable = NULL,
	.install = GPU_install,
	.uninstall = NULL,
	.ack = Local_APIC_edge_level_ack,
};
*/

void GPU_handler(irqno_t irq, void *data);

void init_GPU(void)
{
	int bus,device,function;
	unsigned int index = 0;
	unsigned int value = 0;
	unsigned long * tmp = NULL;
	unsigned int * ptr = NULL;
	unsigned char *start,*end;
	int i;
	unsigned int flags;

	unsigned int stolen_size;
	unsigned int gtt_size;
	unsigned int gtt_total;

	dbgprint("-------------------------------------------------------\n");

	for(bus = 0;bus <= 255;bus++)
		for(device = 0;device <= 31;device++)
			for(function = 0;function <= 7;function++)
			{
				value = Read_PCI_Config(bus,device,function,0);
				if((value & 0xffff) != 0x8086)	//PCH_PCI_HBA.VendorID
					continue;
				value = Read_PCI_Config(bus,device,function,8);
				if(((value >> 24) & 0xff) != 0x06)	//PCH_PCI_HBA.ClassCode
					continue;
				if(((value >> 16) & 0xff) != 0x01)	//PCH_PCI_HBA.SubClass
					continue;

				analysis_PCI_Config(&PCH_PCI_HBA,bus,device,function);
				dbgprint("Intel PCH VendorID:%#06x,DeviceID:%#06x,ClassCode:%#06x,SubClass:%#06x\n", PCH_PCI_HBA.VendorID, PCH_PCI_HBA.DeviceID, PCH_PCI_HBA.ClassCode, PCH_PCI_HBA.SubClass);

				goto analysis_intel_PCH;
			}
analysis_intel_PCH:
	switch(PCH_PCI_HBA.DeviceID & 0xff00)
	{
		case 0x3b00:
			dbgprint("Found Ibex Peak PCH\n");
			break;
		case 0x1c00:
			dbgprint("Found CougarPoint PCH\n");
			break;
		case 0x1e00:
			dbgprint("Found PantherPoint PCH\n");
			break;
		case 0x8c00:
			dbgprint("Found LynxPoint PCH\n");
			break;
		case 0x9c00:
			dbgprint("Found LynxPoint LP PCH\n");
			break;
		case 0x8c80:
			dbgprint("Found WildcatPoint PCH\n");
			break;
		case 0x9c80:
			dbgprint("Found WildcatPoint LP PCH\n");
			break;
		case 0xa100:
			dbgprint("Found SunrisePoint PCH\n");
			break;
		case 0x9d00:
			dbgprint("Found SunrisePoint LP PCH\n");
			break;
		case 0xa280:
			dbgprint("Found Kaby Lake PCH (KBP)\n");
			break;
		case 0xa300:
			dbgprint("Found Cannon Lake PCH (CNP)\n");
			break;
		case 0x9d80:
			dbgprint("Found Cannon Lake LP PCH (CNP-LP)\n");
			break;
		case 0x0280:
		case 0x0680:
			dbgprint("Found Comet Lake PCH (CMP)\n");
			break;
		case 0xa380:
			dbgprint("Found Comet Lake V PCH (CMP-V)\n");
			break;
		case 0x3480:
			dbgprint("Found Ice Lake PCHn");
			break;
		case 0x4b00:
			dbgprint("Found Mule Creek Canyon PCH\n");
			break;
		case 0xa080:
		case 0x4380:
			dbgprint("Found Tiger Lake LP PCH\n");
			break;
		case 0x4d80:
		case 0x3880:
			dbgprint("Found Jasper Lake PCH\n");
			break;
		default:
			break; 
	}

	////0x48
	value = Read_PCI_Config(bus,device,function,0x48);
	infoprint("Memory Base Address(MBA):%x + %x\n",(unsigned long)Read_PCI_Config(bus,device,function,0x4c), value);

	dbgprint("-------------------------------------------------------\n");

	for(bus = 0;bus <= 255;bus++)
		for(device = 0;device <= 31;device++)
			for(function = 0;function <= 7;function++)
			{
				value = Read_PCI_Config(bus,device,function,0);
				if((value & 0xffff) != 0x8086)	//GPU_PCI_HBA.VendorID
					continue;
				value = Read_PCI_Config(bus,device,function,8);
				if(((value >> 24) & 0xff) != 0x03)	//GPU_PCI_HBA.ClassCode
					continue;
				if(((value >> 16) & 0xff) != 0x00)	//GPU_PCI_HBA.SubClass
					continue;

				dbgprint("-------------------------------------------------------\n");

				analysis_PCI_Config(&GPU_PCI_HBA,bus,device,function);

				for(i = 0;i < sizeof(GPU_id_list)/sizeof(struct pci_device_id);i++)
					if((GPU_id_list[i].VendorID == GPU_PCI_HBA.VendorID) && (GPU_id_list[i].DeviceID == GPU_PCI_HBA.DeviceID))
					{
						dbgprint("Intel GPU %s gen=%d VendorID:%#06x,DeviceID:%#06x\n", GPU_id_list[i].name, GPU_id_list[i].platform, GPU_id_list[i].VendorID, GPU_id_list[i].DeviceID);
						goto analysis_intel_GPU;
					}
			}

analysis_intel_GPU:

	dbgprint("-------------------------------------------------------\n");	

	////0x00
	value = Read_PCI_Config(bus,device,function,0x0);
	infoprint("Vendor Identification Number(VID):%#06x\n",value & 0xffff);
	////0x02
	infoprint("Device Identification Number-LSB(DID_LSB):%#06x\n",value >> 16 & 0x3);
	infoprint("Device Identification Number-SKU(DID_SKU):%#06x\n",value >> 18 & 0x3);
	infoprint("Device Identification Number-MSB(DID_MSB):%#06x\n",value >> 20 & 0xfff);

	////0x04
	value = Read_PCI_Config(bus,device,function,0x4);
	infoprint("I/O Access Enable(IOAE):%#06x\n",value & 0x1);
	infoprint("Bus Master Enable(BME):%#06x\n",value >> 2 & 0x1);
	infoprint("Special Cycle Enable(SCE):%#06x\n",value >> 3 & 0x1);
	infoprint("Memory Write and Invalidate Enable(MWIE):%#06x\n",value >> 4 & 0x1);
	infoprint("Video Palette Snooping(VPS):%#06x\n",value >> 5 & 0x1);
	infoprint("Parity Error Enable(PER):%#06x\n",value >> 6 & 0x1);
	infoprint("Wait Cycle Control(WCC):%#06x\n",value >> 7 & 0x1);
	infoprint("SERR Enable(SEN):%#06x\n",value >> 8 & 0x1);
	infoprint("Fast Back-to-Back(FB2B):%#06x\n",value >> 9 & 0x1);
	infoprint("Interrupt Disable(INTDIS):%#06x\n",value >> 10 & 0x1);
	////0x06
	infoprint("Interrupt Status(INTSTS):%#06x\n",value >> 19 & 0x1);
	infoprint("Capability List(CLIST):%#06x\n",value >> 20 & 0x1);
	infoprint("66 MHz PCI Capable(C66):%#06x\n",value >> 21 & 0x1);
	infoprint("User Defined Format(UDF):%#06x\n",value >> 22 & 0x1);
	infoprint("Fast Back-to-Back(FB2B):%#06x\n",value >> 23 & 0x1);
	infoprint("Master Data Parity Error Detected(DPD):%#06x\n",value >> 24 & 0x1);
	infoprint("DEVSEL Timing(DEVT):%#06x\n",value >> 25 & 0x3);
	infoprint("Signaled Target Abort Status(STAS):%#06x\n",value >> 27 & 0x1);
	infoprint("Received Target Abort Status(RTAS):%#06x\n",value >> 28 & 0x1);
	infoprint("Received Master Abort Status(RMAS):%#06x\n",value >> 29 & 0x1);
	infoprint("Signaled System Error(SSE):%#06x\n",value >> 30 & 0x1);
	infoprint("Detected Parity Error(DPE):%#06x\n",value >> 31 & 0x1);

	////0x08
	value = Read_PCI_Config(bus,device,function,0x8);
	infoprint("Revision Identification Number(RID):%#06x\n",value & 0xf);
	infoprint("Revision Identification Number MSB(RID_MSB):%#06x\n",value >> 16 & 0xf);
	////0x09
	infoprint("Programming Interface(PI):%#06x\n",value >> 8 & 0xff);
	infoprint("Sub-Class Code(SUBCC):%#06x\n",value >> 16 & 0xff);
	infoprint("Base Class Code(BCC):%#06x\n",value >> 23 & 0xff);

	////0x0c
	value = Read_PCI_Config(bus,device,function,0xc);
	infoprint("Cache Line Size(CLS):%#06x\n",value & 0xff);
	////0x0d
	infoprint("Master Latency Timer Count Value(MLTCV):%#06x\n",value >> 8 & 0xff);
	////0x0e
	infoprint("Header Code(H):%#06x\n",value >> 16 & 0x7f);
	infoprint("Multi Function Status(MFUNC):%#06x\n",value >> 23 & 0x1);
	////0x0f
	infoprint("BIST Supported(BISTS):%#06x\n",value >> 31 & 0x1);

	////0x10
	value = Read_PCI_Config(bus,device,function,0x10);
	infoprint("Memory Type(MEMTYP):%#06x\n",value >> 1 & 0x3);
	infoprint("Prefetchable Memory(PREFMEM):%#06x\n",value >> 3 & 0x1);
	infoprint("Address Mask(ADMSK):%#010x\n",value >> 4 & 0x3ffff);
	infoprint("Memory Base Address(MBA):%#018lx\n",((unsigned long)Read_PCI_Config(bus,device,function,0x14)) & 0x7f, value & 0xffc00000);
	infoprint("Reserved for Memory Base Address(RSVDRW):%x-%x\n",((unsigned long)Read_PCI_Config(bus,device,function,0x14)) & 0xffffff80, value);

	////0x18
	value = Read_PCI_Config(bus,device,function,0x18);
	infoprint("Memory Type(MEMTYP):%#06x\n",value >> 1 & 0x3);
	infoprint("Prefetchable Memory(PREFMEM):%#06x\n",value >> 3 & 0x1);
	infoprint("Address Mask(ADMSK):%#010x\n",value >> 4 & 0x3ffff);
	infoprint("256 MB Address Mask(ADMSK256):%#010x\n",value >> 27 & 0x1);
	infoprint("512 MB Address Mask(ADMSK512):%#010x\n",value >> 28 & 0x1);
	infoprint("Memory Base Address(MBA):%x-%x\n",((unsigned long)Read_PCI_Config(bus,device,function,0x1c) ) & 0x7f, value % 0xe0000000);
	infoprint("Reserved for Memory Base Address(RSVDRW):%#018lx\n",((unsigned long)Read_PCI_Config(bus,device,function,0x1c)) & 0xffffff80, value & 0x00000000);

	////0x20
	value = Read_PCI_Config(bus,device,function,0x20);
	infoprint("Memory/IO Space(MIOS):%#06x\n",value & 0x1);
	infoprint("Memory Type(MEMTYPE):%#06x\n",value >> 1 & 0x3);
	infoprint("IO Base Address(IOBASE):%#06x\n",value & 0xffc0);

	////0x2c
	value = Read_PCI_Config(bus,device,function,0x2c);
	infoprint("Subsystem Vendor ID(SUBVID):%#06x\n",value & 0xffff);
	////0x2e
	infoprint("Subsystem Identification(SUBID):%#06x\n",value >> 16 & 0xffff);

	////0x30
	value = Read_PCI_Config(bus,device,function,0x30);
	infoprint("ROM BIOS Enable(RBE):%#06x\n",value & 0x1);
	infoprint("Address Mask(ADMSK):%#06x\n",value >> 11 & 0x7f);
	infoprint("ROM Base Address(RBA):%#06x\n",value & 0xfffc0000);

	////0x34
	value = Read_PCI_Config(bus,device,function,0x34);
	infoprint("Capabilities Pointer Value(CPV):%#06x\n",value & 0xff);

	////0x3c
	value = Read_PCI_Config(bus,device,function,0x3c);
	infoprint("Interrupt Connection(INTCON):%#06x\n",value & 0xff);
	////0x3d
	infoprint("Interrupt Pin(INTPIN):%#06x\n",value >> 8 & 0xff);
	////0x3e
	infoprint("Minimum Grant Value(MGV):%#06x\n",value >> 16 & 0xff);
	////0x3f
	infoprint("Maximum Latency Value(MLV):%#06x\n",value >> 24 & 0xff);

	////0x40
	value = Read_PCI_Config(bus,device,function,0x40);
	infoprint("Capability Identifier(CAP_ID):%#06x\n",value & 0xff);
	infoprint("Next Capability Pointer(NEXT_CAP):%#06x\n",value >> 8 & 0xff);
	////0x42
	infoprint("CAPID Length(CAPIDLEN):%#06x\n",value >> 16 & 0xff);
	infoprint("CAPID Version(CAPID_VER):%#06x\n",value >> 24 & 0xf);

	////0x44
	value = Read_PCI_Config(bus,device,function,0x44);
	infoprint("DDR3L_EN:%#06x\n",value & 0x1);
	infoprint("DDR_WRTVREF:%#06x\n",value >> 1 & 0x1);
	infoprint("OC_ENABLED_DSKU:%#06x\n",value >> 2 & 0x1);
	infoprint("DDR_OVERCLOCK:%#06x\n",value >> 3 & 0x1);
	infoprint("CRID:%#06x\n",value >> 4 & 0xf);
	infoprint("CDID:%#06x\n",value >> 8 & 0x3);
	infoprint("DIDOE:%#06x\n",value >> 10 & 0x1);
	infoprint("IGD:%#06x\n",value >> 11 & 0x1);
	infoprint("PDCD:%#06x\n",value >> 12 & 0x1);
	infoprint("X2APIC_EN:%#06x\n",value >> 13 & 0x1);
	infoprint("DDPCD:%#06x\n",value >> 14 & 0x1);
	infoprint("CDD:%#06x\n",value >> 15 & 0x1);
	infoprint("FUFRD:%#06x\n",value >> 16 & 0x1);
	infoprint("D1NM:%#06x\n",value >> 17 & 0x1);
	infoprint("PCIE_RATIO_DIS:%#06x\n",value >> 18 & 0x1);
	infoprint("DDRSZ:%#06x\n",value >> 19 & 0x3);
	infoprint("PEGG2DIS:%#06x\n",value >> 21 & 0x1);
	infoprint("DMIG2DIS:%#06x\n",value >> 22 & 0x1);
	infoprint("VTDD:%#06x\n",value >> 23 & 0x1);
	infoprint("FDEE:%#06x\n",value >> 24 & 0x1);
	infoprint("ECCDIS:%#06x\n",value >> 25 & 0x1);
	infoprint("DW:%#06x\n",value >> 26 & 0x1);
	infoprint("PELWUD:%#06x\n",value >> 27 & 0x1);
	infoprint("PEG10D:%#06x\n",value >> 28 & 0x1);
	infoprint("PEG11D:%#06x\n",value >> 29 & 0x1);
	infoprint("PEG12D:%#06x\n",value >> 30 & 0x1);
	infoprint("DHDAD:%#06x\n",value >> 31 & 0x1);

	////0x48
	value = Read_PCI_Config(bus,device,function,0x48);
	infoprint("SPEGFX1:%#06x\n",value & 0x1);
	infoprint("DPEGFX1:%#06x\n",value >> 1 & 0x1);
	infoprint("SPARE2:%#06x\n",value >> 2 & 0x1);
	infoprint("SPARE3:%#06x\n",value >> 3 & 0x1);
	infoprint("DMFC:%#06x\n",value >> 4 & 0x7);
	infoprint("DDD:%#06x\n",value >> 7 & 0x1);
	infoprint("SPARE10_8:%#06x\n",value >> 8 & 0x7);
	infoprint("SPARE15_12:%#06x\n",value >> 12 & 0xf);
	infoprint("PEGX16D:%#06x\n",value >> 16 & 0x1);
	infoprint("ADDGFXCAP:%#06x\n",value >> 17 & 0x1);
	infoprint("ADDGFXEN:%#06x\n",value >> 18 & 0x1);
	infoprint("PKGTYP:%#06x\n",value >> 19 & 0x3);
	infoprint("PEGG3_DIS:%#06x\n",value >> 20 & 0x1);
	infoprint("PLL_REF100_CFG:%#06x\n",value >> 21 & 0x7);
	infoprint("SOFTBIN:%#06x\n",value >> 24 & 0x1);
	infoprint("CACHESZ:%#06x\n",value >> 25 & 0x7);
	infoprint("SMT:%#06x\n",value >> 28 & 0x1);
	infoprint("OC_ENABLED:%#06x\n",value >> 29 & 0x1);
	infoprint("OC_CTL_DSKU_DIS:%#06x\n",value >> 30 & 0x1);
	infoprint("SPARE31:%#06x\n",value >> 31 & 0x1);

	////0x50
	value = Read_PCI_Config(bus,device,function,0x50);
	infoprint("GGC Lock(GGCLCK):%#06x\n",value & 0x1);
	infoprint("IGD VGA Disable(IVD):%#06x\n",value >> 1 & 0x1);
	infoprint("Graphics Mode Select(GMS):%#06x\n",value >> 3 & 0x1f);
	infoprint("GTT Graphics Memory Size(GGMS):%#06x\n",value >> 8 & 0x3);
	infoprint("Versatile Acceleration Mode Enable(VAMEN):%#06x\n",value >> 14 & 0x1);

	////0x54
	value = Read_PCI_Config(bus,device,function,0x54);
	infoprint("D0EN:%#06x\n",value & 0x1);
	infoprint("D1F2EN:%#06x\n",value >> 1 & 0x1);
	infoprint("D1F1EN:%#06x\n",value >> 2 & 0x1);
	infoprint("D1F0EN:%#06x\n",value >> 3 & 0x1);
	infoprint("D2EN:%#06x\n",value >> 4 & 0x1);
	infoprint("D3EN:%#06x\n",value >> 5 & 0x1);
	infoprint("D4EN:%#06x\n",value >> 7 & 0x1);
	infoprint("D7EN:%#06x\n",value >> 14 & 0x1);

	////0x5c
	value = Read_PCI_Config(bus,device,function,0x5c);
	infoprint("Lock(LOCK):%#06x\n",value & 0x1);
	infoprint("Graphics Base of Stolen Memory (BDSM):%#010x\n",value & 0xfff00000);

	////0x60
	value = Read_PCI_Config(bus,device,function,0x60);
	infoprint("Reserved R/W(ReservedRW):%#06x\n",value & 0xffff);
	////0x62
	infoprint("Untrusted Aperture Size Low(LHSASL):%#06x\n",value >> 17 & 0x1);
	infoprint("Untrusted Aperture Size High(LHSASH):%#06x\n",value >> 18 & 0x1);
	infoprint("Reserved R/W(RSVDRW):%#06x\n",value >> 20 & 0xf);

	////0x90
	value = Read_PCI_Config(bus,device,function,0x90);
	infoprint("Capability ID(CAPID):%#06x\n",value & 0xff);
	infoprint("Pointer to Next Capability(POINTNEXT):%#06x\n",value >> 8 & 0xff);
	////0x92
	infoprint("MSI Enable(MSIEN):%#06x\n",value >> 16 & 0x1);
	infoprint("Multiple Message Capable(MMC):%#06x\n",value >> 17 & 0x7);
	infoprint("Multiple Message Enable(MME):%#06x\n",value >> 20 & 0x7);
	infoprint("64 Bit Capable(CAP64B):%#06x\n",value >> 23 & 0x1);

	////0x94
	value = Read_PCI_Config(bus,device,function,0x94);
	infoprint("Force Dword Align(FDWORD):%#06x\n",value & 0x3);
	infoprint("Message Address(MESSADD):%#010x\n",value & 0xfffffffc);

	////0x98
	value = Read_PCI_Config(bus,device,function,0x98);
	infoprint("Message Data(MESSDATA):%#06x\n",value & 0xffff);

	////0xa4
	value = Read_PCI_Config(bus,device,function,0xa4);
	infoprint("CAP_ID:%#06x\n",value & 0xff);
	infoprint("NEXT_PTR:%#06x\n",value >> 8 & 0xff);
	////0xa6
	infoprint("Capability Length(CAP_LEN):%#06x\n",value >> 16 & 0xff);
	infoprint("TXP Capability(TXP_CAP):%#06x\n",value >> 24 & 0x1);
	infoprint("FLR Capability(FLR_CAP):%#06x\n",value >> 25 & 0x1);

	////0xa8
	value = Read_PCI_Config(bus,device,function,0xa8);
	infoprint("Initiate Function Level Reset(INIT_FLR):%#06x\n",value & 0x1);
	////0xa9
	infoprint("Transactions Pending(TP):%#06x\n",value >> 16 & 0x1);

	////0xd0
	value = Read_PCI_Config(bus,device,function,0xd0);
	infoprint("Capability Identifier(CAP_ID):%#06x\n",value & 0xff);
	infoprint("Next Capability Pointer(NEXT_PTR):%#06x\n",value >> 8 & 0xff);
	////0xd2
	infoprint("Version(VER):%#06x\n",value >> 16 & 0x7);
	infoprint("PME Clock(PMECLK):%#06x\n",value >> 19 & 0x1);
	infoprint("Device Specific Initialization(DSI):%#06x\n",value >> 21 & 0x1);
	infoprint("D1 Support(D1):%#06x\n",value >> 25 & 0x1);
	infoprint("D2 Support(D2):%#06x\n",value >> 26 & 0x1);
	infoprint("PME Support(PMES):%#06x\n",value >> 27 & 0x1f);

	////0xd4
	value = Read_PCI_Config(bus,device,function,0xd4);
	infoprint("PWRSTAT:%#06x\n",value & 0x3);
	infoprint("PMEEN:%#06x\n",value >> 8 & 0x1);
	infoprint("DSEL:%#06x\n",value >> 9 & 0xf);
	infoprint("DSCALE:%#06x\n",value >> 13 & 0x3);
	infoprint("PMESTS:%#06x\n",value >> 15 & 0x1);

	////0xe0
	value = Read_PCI_Config(bus,device,function,0xe0);
	infoprint("GMCH Software SMI Event(GSSMIE):%#06x\n",value & 0x1);
	infoprint("Software Flag(SWF):%#06x\n",value >> 1 & 0x7f);
	infoprint("Software Scratch Bits(SWSB):%#06x\n",value >> 8 & 0xff);

	////0xe4
	value = Read_PCI_Config(bus,device,function,0xe4);
	infoprint("GSE Scratch Trigger 0(GSE0):%#06x\n",value & 0xff);
	infoprint("GSE Scratch Trigger 1(GSE1):%#06x\n",value >> 8 & 0xff);
	infoprint("GSE Scratch Trigger 2(GSE2):%#06x\n",value >> 16 & 0xff);
	infoprint("GSE Scratch Trigger 3(GSE3):%#06x\n",value >> 24 & 0xff);

	////0xe8
	value = Read_PCI_Config(bus,device,function,0xe8);
	infoprint("Software SCI Event(GSSCIE):%#06x\n",value & 0x1);
	infoprint("Software scratch bits(SCISB):%#06x\n",value >> 1 & 0x3fff);
	infoprint("SMI or SCI event select(SMISCISEL):%#06x\n",value >> 15 & 0x1);

	////0xfc
	value = Read_PCI_Config(bus,device,function,0xfc);
	infoprint("Device Switching Storage(DSS):%#010x\n",value);

	dbgprint("-------------------------------------------------------\n");	
	infoprint("map BAR0 space to page table\n");

#if 0
	for(start = (unsigned char *)(unsigned long)GPU_PCI_HBA.Base32Address0,end = (unsigned char *)(unsigned long)(GPU_PCI_HBA.Base32Address0 + GPU_PCI_HBA.Base32Limit0);start < end;start += PAGE_2M_SHIFT)
	{
		tmp = Phy_To_Virt(Get_gdt() + (((unsigned long)Phy_To_Virt(start) >> PAGE_GDT_SHIFT) & 0x1ff));
		if (*tmp == 0)
		{
		unsigned long * virtual = kmalloc(PAGE_4K_SIZE,0);
		memset(virtual,0,PAGE_4K_SIZE);
		set_mpl4t(tmp,mk_mpl4t(Virt_To_Phy(virtual),PAGE_KERNEL_GDT));
		}

		tmp = Phy_To_Virt((unsigned long *)(*tmp & (~ 0xfffUL)) + (((unsigned long)Phy_To_Virt(start) >> PAGE_1G_SHIFT) & 0x1ff));
		if(*tmp == 0)
		{
		unsigned long * virtual = kmalloc(PAGE_4K_SIZE,0);
		memset(virtual,0,PAGE_4K_SIZE);
		set_pdpt(tmp,mk_pdpt(Virt_To_Phy(virtual),PAGE_KERNEL_Dir));
		}
	
		tmp = Phy_To_Virt((unsigned long *)(*tmp & (~ 0xfffUL)) + (((unsigned long)Phy_To_Virt(start) >> PAGE_2M_SHIFT) & 0x1ff));
		set_pdt(tmp,mk_pdt((unsigned long)start & PAGE_2M_MASK,PAGE_KERNEL_Page | PAGE_PWT | PAGE_PCD));	
	}
#else
    hal_memio_remap(GPU_PCI_HBA.Base32Address0, GPU_PCI_HBA.Base32Address0, GPU_PCI_HBA.Base32Limit0);
#endif

	infoprint("map BAR2 space to page table\n");

#if 0
	for(start = (unsigned char *)(unsigned long)GPU_PCI_HBA.Base32Address2,end = (unsigned char *)(unsigned long)(GPU_PCI_HBA.Base32Address2 + GPU_PCI_HBA.Base32Limit2);start < end;start += PAGE_2M_SHIFT)
	{
		tmp = Phy_To_Virt(Get_gdt() + (((unsigned long)Phy_To_Virt(start) >> PAGE_GDT_SHIFT) & 0x1ff));
		if (*tmp == 0)
		{
		unsigned long * virtual = kmalloc(PAGE_4K_SIZE,0);
		memset(virtual,0,PAGE_4K_SIZE);
		set_mpl4t(tmp,mk_mpl4t(Virt_To_Phy(virtual),PAGE_KERNEL_GDT));
		}

		tmp = Phy_To_Virt((unsigned long *)(*tmp & (~ 0xfffUL)) + (((unsigned long)Phy_To_Virt(start) >> PAGE_1G_SHIFT) & 0x1ff));
		if(*tmp == 0)
		{
		unsigned long * virtual = kmalloc(PAGE_4K_SIZE,0);
		memset(virtual,0,PAGE_4K_SIZE);
		set_pdpt(tmp,mk_pdpt(Virt_To_Phy(virtual),PAGE_KERNEL_Dir));
		}
	
		tmp = Phy_To_Virt((unsigned long *)(*tmp & (~ 0xfffUL)) + (((unsigned long)Phy_To_Virt(start) >> PAGE_2M_SHIFT) & 0x1ff));
		set_pdt(tmp,mk_pdt((unsigned long)start & PAGE_2M_MASK,PAGE_KERNEL_Page | PAGE_PWT | PAGE_PCD));	
	}
#else
    hal_memio_remap(GPU_PCI_HBA.Base32Address2, GPU_PCI_HBA.Base32Address2, GPU_PCI_HBA.Base32Limit2);
#endif
	tlb_flush();

	dbgprint("-------------------------------------------------------\n");
while(1);	//##############################################################################################################
}

void GPU_handler(irqno_t irq, void *data)
{
	unsigned int DE_IER,SDE_IER;
	unsigned int GT_IIR,DE_IIR,PM_IIR;
	warnprint("GPU_handler\n");

	/* disable master interrupt before clearing iir  */
	DE_IER = intel_uncore_read32(GTTMMADR,0x4400c);			//DEIER
	intel_uncore_write32(GTTMMADR,0x4400c,DE_IER & ~(1 << 31));
	intel_uncore_read32(GTTMMADR,0x4400c);

	SDE_IER = intel_uncore_read32(GTTMMADR,0xc400c);		//SDEIER
	intel_uncore_write32(GTTMMADR,0xc400c,0);
	intel_uncore_read32(GTTMMADR,0xc400c);

	GT_IIR = intel_uncore_read32(GTTMMADR,0x44018);			//GTIIR
	if(GT_IIR)
	{
		intel_uncore_write32(GTTMMADR,0x44018,GT_IIR);
		//GT irq handler
		if(GT_IIR & GT_RENDER_COMMAND_PARSER_USER_INTERRUPT)				//0
		{
			errprint("[GT ERROR]");
			errprint("Render Command Parser User Interrupt:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_DEBUG_INTERRUPT)						//1
		{
			errprint("[GT ERROR]");
			errprint("Render Debug Interrupt:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_MMIO_SYNC_FLUSH_STATUS)					//2
		{
			errprint("[GT ERROR]");
			errprint("Render MMIO Sync Flush Status:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_COMMAND_PARSER_MASTER_ERROR)				//3
		{
			errprint("[GT ERROR]");
			errprint("Render Command Parser Master Error:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_PIPE_CONTROL_NOTIFY)					//4
		{
			errprint("[GT ERROR]");
			errprint("Render PIPE CONTROL Notify:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_L3_PARITY_ERROR)						//5
		{
			errprint("[GT ERROR]");
			errprint("L3 Parity Error:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_TIMEOUT_COUNTER_EXPIRED)					//6
		{
			errprint("[GT ERROR]");
			errprint("Render Timeout Counter Expired:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_PAGE_DIRECTORY_FAULTS)					//7
		{
			errprint("[GT ERROR]");
			errprint("Render Page Directoy Faults:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_PREEMPTION_COMPLETE_INTERRUPT)					//8
		{
			errprint("[GT ERROR]");
			errprint("Preemption Complete Interrupt:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_RENDER_PREF_MONITOR_BUFFER_HALF_FULL_INTERRUPT)			//9
		{
			errprint("[GT ERROR]");
			errprint("Render Perf Monitor Buffer Half Full Interrupt:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_L3_COUNTER_SAVE)							//10
		{
			errprint("[GT ERROR]");
			errprint("L3 Counter Save:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_L3_PARITY_ERROR_SLICE1)						//11
		{
			errprint("[GT ERROR]");
			errprint("L3 Parity Error Slice1:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_VIDEO_CODEC_COMMAND_PARSER_USER_INTERRUPT)			//12
		{
			errprint("[GT ERROR]");
			errprint("VideoCodec Command Parser User Interrupt:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_VIDEO_CODEC_MMIO_SYNC_FLUSH_STATUS)				//14
		{
			errprint("[GT ERROR]");
			errprint("VideoCodec MMIO Sync Flush Status:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_VIDEO_CODEC_COMMAND_PARSER_MASTER_ERROR)				//15
		{
			errprint("[GT ERROR]");
			errprint("VideoCodec Command Parser Master Error:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_VIDEO_CODEC_MI_FLUSH_DW_NOTIFY)					//16
		{
			errprint("[GT ERROR]");
			errprint("VideoCodec MI FLUSH DW Notify:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_VIDEO_CODEC_TIMEOUT_COUNTER_EXPIRED)				//18
		{
			errprint("[GT ERROR]");
			errprint("VideoCodec Timeout Counter Expired:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_VIDEO_CODEC_PAGE_DIRECTORY_FAULTS)				//19
		{
			errprint("[GT ERROR]");
			errprint("VideoCodec Page Directory Faults:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_BLITTER_COMMAND_PARSER_USER_INTERRUPT)				//22
		{
			errprint("[GT ERROR]");
			errprint("Blitter Command Parser User Interrupt:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_BLITTER_MMIO_SYNC_FLUSH_STATUS)					//24
		{
			errprint("[GT ERROR]");
			errprint("Blitter MMIO Sync Flush Status:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_BLITTER_COMMAND_PARSER_MASTER_ERROR)				//25
		{
			errprint("[GT ERROR]");
			errprint("Blitter Command Parser Master Error:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_BLITTER_MI_FLUSH_DW_NOTIFY)					//26
		{
			errprint("[GT ERROR]");
			errprint("Blitter MI FLUSH DW Notify:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & GT_BLITTER_PAGE_DIRECTORY_FAULTS)					//29
		{
			errprint("[GT ERROR]");
			errprint("Blitter Page Directory Faults:%#010x\n",GT_IIR);	
		}

		if(GT_IIR & (GT_BLITTER_COMMAND_PARSER_MASTER_ERROR | GT_VIDEO_CODEC_COMMAND_PARSER_MASTER_ERROR | GT_RENDER_COMMAND_PARSER_MASTER_ERROR))	//25 | 15 | 3
		{
			errprint("i915_capture_reg_state\n");
			errprint("GEN7_ERR_INT:%#010x\n",intel_uncore_read32(GTTMMADR,0x44040));
			errprint("FORCEWAKE_MT:%#010x\n",intel_uncore_read32(GTTMMADR,0xa188));
			errprint("DERRMR:%#010x\n",intel_uncore_read32(GTTMMADR,0x44050));
			errprint("ERROR_GEN6:%#010x\n",intel_uncore_read32(GTTMMADR,0x40a0));
			errprint("DONE_REG:%#010x\n",intel_uncore_read32(GTTMMADR,0x40b0));
			errprint("GAM_ECOCHK:%#010x\n",intel_uncore_read32(GTTMMADR,0x4090));
			errprint("GAC_ECO_BITS:%#010x\n",intel_uncore_read32(GTTMMADR,0x14090));
			errprint("CCID:%#010x\n",intel_uncore_read32(GTTMMADR,0x2180));
			errprint("DEIER:%#010x\n",intel_uncore_read32(GTTMMADR,0x4400c));
			errprint("GTIER:%#010x\n",intel_uncore_read32(GTTMMADR,0x4401c));
			errprint("EIR:%#010x\n",intel_uncore_read32(GTTMMADR,0x20b0));
			errprint("PGTBL_ER:%#010x\n",intel_uncore_read32(GTTMMADR,0x2024));

			errprint("i915_get_extra_instdone\n");
			errprint("GEN7_INSTDONE_1:%#010x\n",intel_uncore_read32(GTTMMADR,0x206c));
			errprint("GEN7_SC_INSTDONE:%#010x\n",intel_uncore_read32(GTTMMADR,0x7100));
			errprint("GEN7_SAMPLER_INSTDONE:%#010x\n",intel_uncore_read32(GTTMMADR,0xe160));
			errprint("GEN7_ROW_INSTDONE:%#010x\n",intel_uncore_read32(GTTMMADR,0xe164));

			errprint("i915_gem_record_fences\n");
			errprint("FENCE_REG_SANDYBRIDGE_0:%#010x\n",intel_uncore_read32(GTTMMADR,0x100000));

			errprint("i915_gem_record_rings\n");
			errprint("RC_PSMI_CONTROL:%#010x\n",intel_uncore_read32(GTTMMADR,0x2050));
			errprint("RING_FAULT_REG:%#010x\n",intel_uncore_read32(GTTMMADR,0x4094));
			errprint("RING_SYNC_0:%#010x\n",intel_uncore_read32(GTTMMADR,0x2040));
			errprint("RING_SYNC_1:%#010x\n",intel_uncore_read32(GTTMMADR,0x2044));
			errprint("RING_SYNC_2:%#010x\n",intel_uncore_read32(GTTMMADR,0x2048));
			errprint("RING_DMA_FADD:%#010x\n",intel_uncore_read32(GTTMMADR,0x2078));
			errprint("RING_IPEIR:%#010x\n",intel_uncore_read32(GTTMMADR,0x2064));
			errprint("RING_IPEHR:%#010x\n",intel_uncore_read32(GTTMMADR,0x2068));
			errprint("RING_INSTDONE:%#010x\n",intel_uncore_read32(GTTMMADR,0x206c));
			errprint("RING_INSTPS:%#010x\n",intel_uncore_read32(GTTMMADR,0x2070));
			errprint("RING_BBADDR:%#010x\n",intel_uncore_read32(GTTMMADR,0x2140));
			errprint("RING_BBSTATE:%#010x\n",intel_uncore_read32(GTTMMADR,0x2110));
			errprint("RING_INSTPM:%#010x\n",intel_uncore_read32(GTTMMADR,0x20c0));
			errprint("RING_ACTHD:%#010x\n",intel_uncore_read32(GTTMMADR,0x2074));
			errprint("READ_HEAD:%#010x\n",intel_uncore_read32(GTTMMADR,0x2034));
			errprint("READ_TAIL:%#010x\n",intel_uncore_read32(GTTMMADR,0x2030));
			errprint("READ_CTL:%#010x\n",intel_uncore_read32(GTTMMADR,0x203c));
			errprint("RENDER_HWS_PGA:%#010x\n",intel_uncore_read32(GTTMMADR,0x4080));
			errprint("RING_MODE_GEN7:%#010x\n",intel_uncore_read32(GTTMMADR,0x229c));
			errprint("RING_PP_DIR_BASE:%#010x\n",intel_uncore_read32(GTTMMADR,0x2228));

			errprint("i915_report_and_clear_eir\n");
			errprint("PGTBL_ER:%#010x\n",intel_uncore_read32(GTTMMADR,0x2024));
			errprint("INSTPM:%#010x\n",intel_uncore_read32(GTTMMADR,0x20c0));
			errprint("IPEIR:%#010x\n",intel_uncore_read32(GTTMMADR,0x2064));
			errprint("IPEHR:%#010x\n",intel_uncore_read32(GTTMMADR,0x2068));
			errprint("INSTPS:%#010x\n",intel_uncore_read32(GTTMMADR,0x2070));
			errprint("ACTHD:%#010x\n",intel_uncore_read32(GTTMMADR,0x2074));
			errprint("EIR:%#010x\n",intel_uncore_read32(GTTMMADR,0x20b0));
		}

		if(GT_IIR & (GT_RENDER_L3_PARITY_ERROR | GT_L3_PARITY_ERROR_SLICE1))	//5 | 11
		{
			errprint("ivybridge_parity_error_irq_handler\n");
			errprint("GTIMR:%#010x\n",intel_uncore_read32(GTTMMADR,0x44014));			
		}
	}

	DE_IIR = intel_uncore_read32(GTTMMADR,0x44008);			//DEIIR
	if(DE_IIR)
	{
		intel_uncore_write32(GTTMMADR,0x44008,DE_IIR);
		//Display Engine irq handler
		if(DE_IIR & DE_MASTER_INTERRUPT_CONTROL)					//31
		{
			errprint("[DE ERROR]");
			errprint("Master Interrupt Control:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_ERROR_INTERRUPT_COMBINED)					//30
		{
			unsigned int err_int;
			errprint("[DE ERROR]");
			errprint("Error Interrupts Combined:%#010x\n",DE_IIR);
			err_int = intel_uncore_read32(GTTMMADR,0x44040);
			errprint("GEN7_ERR_INT:%#010x\n",err_int);
			if(err_int & (1 << 31))
				errprint("Poison interrupt\n");
		}

		if(DE_IIR & DE_GSE)								//29
		{
			errprint("[DE ERROR]");
			errprint("GSE:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_PCH_DISPLAY_INTERRUPT_EVENT)					//28
		{
			errprint("[DE ERROR]");
			errprint("PCH Display interrupt event:%#010x\n",DE_IIR);
			errprint("SDEIIR:%#010x\n",intel_uncore_read32(GTTMMADR,0xc4008));
			errprint("SERR_INT:%#010x\n",intel_uncore_read32(GTTMMADR,0xc4040));
			errprint("PORT_HOTPLUG:%#010x\n",intel_uncore_read32(GTTMMADR,0xc4030));
		}

		if(DE_IIR & DE_DISPLAY_A_HOTPLUG)						//27
		{
			errprint("[DE ERROR]");
			errprint("DisplayPort A Hotplug:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_AUX_CHANNEL_A)							//26
		{
			errprint("[DE ERROR]");
			errprint("AUX Channel A:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_DPST_HISTOGRAM_EVENT)						//25
		{
			errprint("[DE ERROR]");
			errprint("DPST histogram event:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_DPST_PHASE_IN_EVENT)						//24
		{
			errprint("[DE ERROR]");
			errprint("DPST phase in event:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_AUDIO_CODEC_INTERRUPTS_COMBINED)					//20
		{
			errprint("[DE ERROR]");
			errprint("Audio Codec Interrupts Combined:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_SRD_INTERRUPTS_COMBINED)						//19
		{
			errprint("[DE ERROR]");
			errprint("SRD Interrupts Combined:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_GTC_CPU_INTERRUPTS_COMBINED)					//15
		{
			errprint("[DE ERROR]");
			errprint("GTC CPU Interrupts Combined:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_SPRITE_PLANE_FLIP_DONE_C)					//14
		{
			errprint("[DE ERROR]");
			errprint("Sprite Plane Flip Done C:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_PRIMARY_PLANE_FLIP_DONE_C)					//13
		{
			errprint("[DE ERROR]");
			errprint("Primary Plane Flip Done C:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_LINE_COMPARE_PIPE_C)						//12
		{
			errprint("[DE ERROR]");
			errprint("Line Compare Pipe C:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_V_SYNC_PIPE_C)							//11
		{
			errprint("[DE ERROR]");
			errprint("Vsync Pipe C:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_V_BLANK_PIPE_C)							//10
		{
			errprint("[DE ERROR]");
			errprint("Vblank Pipe C:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_SPRITE_PLANE_FLIP_DONE_B)					//9
		{
			errprint("[DE ERROR]");
			errprint("Sprite Plane Flip Done B:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_PRIMARY_PLANE_FLIP_DONE_B)					//8
		{
			errprint("[DE ERROR]");
			errprint("Primary Plane Flip Done B:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_LINE_COMPARE_PIPE_B)						//7
		{
			errprint("[DE ERROR]");
			errprint("Line Compare Pipe B:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_V_SYNC_PIPE_B)							//6
		{
			errprint("[DE ERROR]");
			errprint("Vsync Pipe B:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_V_BLANK_PIPE_B)							//5
		{
			errprint("[DE ERROR]");
			errprint("Vblank Pipe B:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_SPRITE_PLANE_FLIP_DONE_A)					//4
		{
			errprint("[DE ERROR]");
			errprint("Sprite Plane Flip Done A:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_PRIMARY_PLANE_FLIP_DONE_A)					//3
		{
			errprint("[DE ERROR]");
			errprint("Primary Plane Flip Done A:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_LINE_COMPARE_PIPE_A)						//2
		{
			errprint("[DE ERROR]");
			errprint("Line Compare Pipe A:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_V_SYNC_PIPE_A)							//1
		{
			errprint("[DE ERROR]");
			errprint("Vsync Pipe A:%#010x\n",DE_IIR);	
		}

		if(DE_IIR & DE_V_BLANK_PIPE_A)							//0
		{
			errprint("[DE ERROR]");
			errprint("Vblank Pipe A:%#010x\n",DE_IIR);	
		}
	}

	PM_IIR = intel_uncore_read32(GTTMMADR,0x44028);			//PMIIR
	if(PM_IIR)
	{
		intel_uncore_write32(GTTMMADR,0x44028,PM_IIR);
		//Power Management irq handler
		if(PM_IIR & PM_RENDER_GEYSERVILLE_DOWN_EVALUATION_INTERVAL)			//1
		{
			errprint("[PM ERROR]");
			errprint("Render Geyserville Down Evaluation Interval:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_RENDER_GEYSERVILLE_UP_EVALUATION_INTERVAL)			//2
		{
			errprint("[PM ERROR]");
			errprint("Render Geyserville UP Evaluation Interval:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_RP_DOWN_THRESHOLD)						//4
		{
			errprint("[PM ERROR]");
			errprint("RP DOWN Threshold:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_RP_UP_THRESHOLD)							//5
		{
			errprint("[PM ERROR]");
			errprint("RP UP Threshold:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_RENDER_FREQUENCY_DOWNWARD_TIMEOUT_DURING_RC6)			//6
		{
			errprint("[PM ERROR]");
			errprint("Render Frequency Downward Timeout During RC6:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_VIDEOENH_COMMAND_PARSER_USER_INTERRUPT)				//10
		{
			errprint("[PM ERROR]");
			errprint("VideoEnh Command Parser User Interrupt:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_VIDEOENH_MMIO_SYNC_FLUSH_STATUS)					//11
		{
			errprint("[PM ERROR]");
			errprint("VideoEnh MMIO Sync Flush Status:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_VIDEOENH_COMMAND_PARSER_MASTER_ERROR)				//12
		{
			errprint("[PM ERROR]");
			errprint("VideoEnh Command Parser Master Error:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_VIDEOENH_MI_FLUSH_DW_NOTIFY)					//13
		{
			errprint("[PM ERROR]");
			errprint("VideoEnh MI FLUSH DW Notify:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_PCU_THERMAL_EVENT)						//24
		{
			errprint("[PM ERROR]");
			errprint("PCU Thermal Event:%#010x\n",PM_IIR);	
		}

		if(PM_IIR & PM_PCU_PCODE2DRIVER_MAILBOX_EVENT)					//25
		{
			errprint("[PM ERROR]");
			errprint("PCU Pcode2driver Mailbox Event:%#010x\n",PM_IIR);	
		}
	}

	intel_uncore_write32(GTTMMADR,0x4400c,DE_IER);			//DEIER
	intel_uncore_read32(GTTMMADR,0x4400c);

	intel_uncore_write32(GTTMMADR,0xc400c,SDE_IER);			//SDEIER
	intel_uncore_read32(GTTMMADR,0xc400c);
}

#define DRV_NAME "inte lgpu"
#define DRV_VERSION "0.1"

#define DEV_NAME "gpu0"

typedef struct _device_extension {
    unsigned long reserved;
} device_extension_t;

static iostatus_t gpu_driver_write(device_object_t *device, io_request_t *ioreq)
{
    iostatus_t status = IO_SUCCESS;

    ioreq->io_status.status = status;
    io_complete_request(ioreq);
    return status;
}

static iostatus_t gpu_driver_enter(driver_object_t *driver)
{
    iostatus_t status;
    
    device_object_t *devobj;
    device_extension_t *extension;

    /* 初始化一些其它内容 */
    status = io_create_device(driver, sizeof(device_extension_t), DEV_NAME, DEVICE_TYPE_VIRTUAL_CHAR, &devobj);

    if (status != IO_SUCCESS) {
        keprint(PRINT_ERR "gpu_driver_enter: create device failed!\n");
        return status;
    }
    /* neighter io mode */
    devobj->flags = 0;
    extension = (device_extension_t *)devobj->device_extension;

    // init 
    init_GPU();

    return status;
}

static iostatus_t gpu_driver_exit(driver_object_t *driver)
{
    /* 遍历所有对象 */
    device_object_t *devobj, *next;
    /* 由于涉及到要释放devobj，所以需要使用safe版本 */
    list_for_each_owner_safe (devobj, next, &driver->device_list, list) {
        io_delete_device(devobj);   /* 删除每一个设备 */
    }

    string_del(&driver->name); /* 删除驱动名 */
    return IO_SUCCESS;
}

static iostatus_t gpu_driver_func(driver_object_t *driver)
{
    iostatus_t status = IO_SUCCESS;
    
    /* 绑定驱动信息 */
    driver->driver_enter = gpu_driver_enter;
    driver->driver_exit = gpu_driver_exit;


    driver->dispatch_function[IOREQ_WRITE] = gpu_driver_write;

    /* 初始化驱动名字 */
    string_new(&driver->name, DRV_NAME, DRIVER_NAME_LEN);
#ifdef DEBUG_DRV
    keprint(PRINT_DEBUG "gpu_driver_func: driver name=%s\n",
        driver->name.text);
#endif
    
    return status;
}

static __init void gpu_driver_entry(void)
{
    if (driver_object_create(gpu_driver_func) < 0) {
        keprint(PRINT_ERR "[driver]: %s create driver failed!\n", __func__);
    }
}

driver_initcall(gpu_driver_entry);
